Algorithmes gloutons
Table des matières
1. Le problème du rendu de monnaie
On appelle système de monnaie la donnée d'une liste strictement croissante d'entiers représentant l'ensemble des valeurs des différentes pièces et billets d'une monnaie. Le système de l'euro est représenté par la liste l = [1, 2, 5, 10, 20, 50, 100, 200, 500].
Étant donné une somme $s\in\N$ à payer et un système de monnaie, le problème du rendu de monnaie consiste à déterminer comment réaliser la somme $s$ avec les valeurs existantes, en minimisant le nombre de pièces/billets utilisés. On supposera que la liste l contient la valeur $1$, ce qui assure que toute somme peut être réalisée.
La stratégie gloutonne consiste à choisir à chaque étape la plus grande valeur qui reste inférieure à la somme restante.
- Appliquer la stratégie gloutonne pour rendre $154$€ avec le système de l'euro.
- Écrire une fonction
plus_grande_valeurqui prend en argument un entier $r\in\N^*$, représentant la somme restante à payer et une listelreprésentant un système de monnaie, et renvoie la plus grande valeur du système qui soit $\leq r$. - Écrire une fonction
renduqui prend en argument une somme $s$ et une listelreprésentant un système de monnaie, et renvoie une liste contenant les valeurs utilisées pour payer la somme $s$, en utilisant la stratégie gloutonne. Donner un exemple de système de monnaie et d'une somme $s$, pour lesquels la stratégie gloutonne ne renvoie pas une solution optimale.
Un système de monnaie est dit canonique si la méthode gloutonne renvoie toujours une solution optimale. Le système de l'euro est canonique.
Réalisation, par recherche exhaustive
On suppose ici qu'un système de monnaie l ne contient plus nécessairement la valeur $1$.
- Écrire une fonction récursive
peut_realiserqui prend un système de monnaielet une sommeset qui renvoieTruesi on peut réaliser (pas nécessairement par la méthode gloutonne) la sommesen sommant des valeurs de la listel. - ★ L'approche récursive précédente est inefficace. Réimplémenter
peut_realiserde manière itérative, en construisant petit à petit une listertelle quer[i]vailleTruesi et seulement si $i$ est réalisable.
2. Réservation de salle
On s'intéresse à un problème de réservation d'une salle, sur une période de plusieurs jours, à partir d'un premier jour.
Chaque demande de réservation est représentée par un couple d'entiers (a, b), où a représente le jour de début de la réservation, et b le jour de fin (inclus). En particulier $a\leq b$ et $a\geq 1$.
On considère une liste l contenant les demandes de réservation. l est une liste de couples, par exemple l = [(1,5), (5,6), (2,3)]. On peut accéder aux jours de début et de fin d'une demande de réservation par l'instruction (deb, fin) = l[i].
Les réservations ne sont pas toutes compatibles entre elles et on souhaite choisir un planning de réservations qui maximise le nombre de réservations. Pour l'exemple précédent, un planning de réservation optimal est donc [(2,3), (5,6)].
La stratégie gloutonne consiste à choisir les réservations par ordre chronologique. À chaque étape on choisit la réservation compatible avec les précédentes qui s'arrête le plus tôt.
- Écrire une fonction
est_liste_reservqui prend en argument une liste de couples d'entiers et renvoieTruesi cette liste représente bien des demandes de réservations, etFalsesinon. Écrire une fonction qui prend en argument la liste
let un entierdreprésentant un jour, et renvoie la demande de réservation qui termine le plus tôt, parmi les réservations qui commencent après (strictement) le jourd. S'il n'y a pas de telle réservation, on renverra la valeur spécialeNone.On pourra éventuellement initialiser une variable à une valeur
None.- Implémenter une fonction
reservation_gloutonnequi prend en argument la listelet renvoie une nouvelle liste contenant les réservations choisies par la méthode gloutonne. La complexité de l'implémentation précédente est quadratique. Proposer une implémentation d'une complexité $O(n\ln n)$.
On pourra utiliser les instructions
ll = [(y,x) for x,y in l]etll.sort(), pour trierllselon l'ordre lexicographique.Justifier que le planning de réservations choisi par la stratégie gloutonne est une réservation optimale.
On pourra commencer par justifier qu'il existe une réservation optimale dont la première réservation est la réservation qui termine le plus tôt.
Maximisation du temps de réservation
- ★ Écrire une fonction qui renvoie un planning de réservation qui maximise le nombre de jours réservés.
3. Couverture minimale
On représente des parties de $\db{0,n-1}$ par des listes de taille $n$ de booléens. On dit qu'une famille $\mc F$ de parties de $\db{0,n-1}$ recouvre $\db{0,n-1}$ si $\bigcup\limits_{A\in\mc F} A = \db{0,n-1}$. L'objectif est d'extraire d'une telle famille une sous-famille couvrante avec le moins de parties possible.
- Écrire une fonction
sous_couverture_minqui prend en argument une famille couvrante de $\db{0,n-1}$, représentée par une liste de parties, et renvoie une sous-famille couvrante construite de manière gloutonne, en cherchant à minimiser le nombre de parties. - Expliciter la complexité de votre implémentation, en fonction de $n$, de $m = |\mc F|$, et/ou de $M = \sum\limits_{A\in\mc F} |A|$.
- Montrer à travers un exemple que l'algorithme glouton précédent n'est pas optimal.
Application : Un ensemble de villes est représenté par un graphe non orienté. On veut installer un nombre minimal d'antennes cellulaires pour couvrir le réseau téléphonique. Chaque antenne est installée dans une ville, et couvre la ville, ainsi que ses villes voisines dans le graphe.
Écrire une fonction qui prend en argument un graphe non orienté $\mc G$, et renvoie une répartition possible des antennes.
- ★ On suppose qu'il existe une couverture optimale avec $m_o$ ensembles. On note $m_g$ le cardinal d'une couverture renvoyée par l'algorithme glouton, et on veut majorer $m_g$.
- On note $r_i$ le nombre d'éléments restants (non couverts) après $i$-étapes de l'algorithme glouton. Montrer que $$r_i\leq n\left(1 - \frac{1}{m_o}\right)^i.$$
- En déduire que $m_g \leq m_o \ln n$.
- ★ Comment améliorer la complexité de votre implémentation ? Une solution optimale est en $O(M)$.
4. Voyageur de commerce
Lors d'une exploration extraterestrielle, $n$ points d'intérêts numérotés de $0$ à $n-1$ ont été déterminés. Un robot doit choisir un chemin à partir de son point initial qui lui permet de passer par tous les points d'intérêts une et une seule fois. L'objectif est de trouver un chemin de longueur totale minimale. Le robot n'a pas besoin de revenir à son point initial à la fin.
Un tel chemin est représenté par une liste de longueur $n$ contenant les points d'intérêts dans leur ordre de visite.
On représente les distances entre chaque paire de points d'intérêt dans une liste de listes globale DISTANCE, que l'on pourra librement utiliser : pour $i,j\in\db{0,n-1}$, l'instruction DISTANCE[i][j] renverra la distance entre les points d'intérêts $i$ et $j$.
Par ailleurs, le point initial du robot est représenté par l'indice $n$ et les distances des points d'intérêts au point initial peuvent être récupérées par des appels DISTANCE[i][n] ou DISTANCE[n][i].
4.1. Préliminaires
On représente un chemin par une liste l de longueur $n$, contenant les numéros des points d'intérêts, dans l'ordre de visite.
- Écrire une fonction
longueur_cheminqui prend en argument un chemin, et renvoie la distance totale que devra parcourir le robot pour réaliser ce chemin, à partir de sa position initiale. - Quel est le nombre de chemins possibles ? Pour $n = 20$ points d'intérêts, est-il envisageable de générer tous les chemins pour trouver le plus court ? Rmq : un ordinateur réalise de l'ordre de $10^9$ opérations par seconde.
- ★ Écrire une fonction récursive
genere_cheminsqui prend en argument $n$ et renvoie la liste de tous les chemins possibles.
4.2. Algorithme glouton par plus proches voisins
Pour générer un chemin le plus court possible, on part du point initial et on procède de manière gloutonne, en choisissant à chaque étape le point d'intérêt non visité le plus proche de notre position.
- Écrire une fonction
plus_proche_voisinqui prend en argument un point d'intérêt $i$, une listevisde points d'intérêts déjà visités et l'entier $n$ et renvoie le point d'intérêt non visité le plus proche de $i$. En cas d'égalité, on renverra le point de plus petit indice. S'il n'y a plus de points d'intérêt, on renverraNone. On ne demande pas d'optimiser la complexité. - Implémenter une fonction
algo_glouton1qui prend en argument $n$ et renvoie un chemin visitant tous les points d'intérêt, implémentant cette stratégie gloutonne. - En considérant un point de départ adéquat, et les points de coordonnées $(0,0)$, $(0, 30)$ et $(0,70)$ comme points d'intérêts, montrer que l'algorithme n'est pas optimal.
4.3. Algorithme glouton par insertions successives
Pour générer un chemin le plus court possible, on part d'un chemin vide, puis à chaque étape, on rajoute le point d'intérêt $i$ au chemin déjà généré, en l'insérant à une position dans le chemin déjà construit, de manière à minimiser la longueur du nouveau chemin.
- Implémenter l'algorithme décrit, sous la forme
algo_glouton2. On veut une complexité quadratique.